home *** CD-ROM | disk | FTP | other *** search
Text File | 2005-01-31 | 47.9 KB | 1,266 lines |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Update Service.
- *
- * The Initial Developer of the Original Code is Ben Goodger.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Ben Goodger <ben@bengoodger.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
- const PREF_APP_ID = "app.id";
- const PREF_APP_VERSION = "app.version";
- const PREF_UPDATE_APP_ENABLED = "app.update.enabled";
- const PREF_UPDATE_APP_AUTOUPDATEENABLED = "app.update.autoUpdateEnabled";
- const PREF_UPDATE_APP_URI = "app.update.url";
- const PREF_UPDATE_APP_UPDATESAVAILABLE = "app.update.updatesAvailable";
- const PREF_UPDATE_APP_INTERVAL = "app.update.interval";
- const PREF_UPDATE_APP_LASTUPDATEDATE = "app.update.lastUpdateDate";
- const PREF_UPDATE_APP_PERFORMED = "app.update.performed";
-
- const PREF_UPDATE_EXTENSIONS_ENABLED = "extensions.update.enabled";
- const PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED = "extensions.update.autoUpdateEnabled";
- const PREF_UPDATE_EXTENSIONS_AUTOUPDATE = "extensions.update.autoUpdate";
- const PREF_UPDATE_EXTENSIONS_COUNT = "extensions.update.count";
- const PREF_UPDATE_EXTENSIONS_INTERVAL = "extensions.update.interval";
- const PREF_UPDATE_EXTENSIONS_LASTUPDATEDATE = "extensions.update.lastUpdateDate";
- const PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD = "extensions.update.severity.threshold";
-
- const PREF_UPDATE_INTERVAL = "update.interval";
- const PREF_UPDATE_SEVERITY = "update.severity";
- const PREF_UPDATE_SHOW_SLIDING_NOTIFICATION = "update.showSlidingNotification";
-
- const nsIExtensionManager = Components.interfaces.nsIExtensionManager;
- const nsIUpdateService = Components.interfaces.nsIUpdateService;
- const nsIUpdateItem = Components.interfaces.nsIUpdateItem;
-
- const UPDATED_EXTENSIONS = 0x01;
- const UPDATED_APP = 0x02;
-
- function APP_NS(aProperty)
- {
- return "http://www.mozilla.org/2004/app-rdf#" + aProperty;
- }
-
- function getOSKey()
- {
- return "windows";
- }
-
- function stackTraceFunctionFormat(aFunctionName)
- {
- var classDelimiter = aFunctionName.indexOf("_");
- var className = aFunctionName.substr(0, classDelimiter);
- if (!className)
- className == "<global>";
- var functionName = aFunctionName.substr(classDelimiter + 1, aFunctionName.length);
- if (!functionName)
- functionName == "<anonymous>";
- return className + "::" + functionName;
- }
-
- function stackTrace(aArguments, aMaxCount)
- {
- dump("=[STACKTRACE]=====================================================\n");
- dump("*** at: " + stackTraceFunctionFormat(aArguments.callee.name) + "()\n");
- var temp = aArguments.callee.caller;
- var count = 0;
- while (temp) {
- dump("*** " + stackTraceFunctionFormat(temp.name) + ")\n");
- temp = temp.arguments.callee.caller;
- if (aMaxCount > 0 && ++count == aMaxCount)
- break;
- }
- dump("==================================================================\n");
- }
-
- var gPref = null;
- var gOS = null;
- var gRDF = null;
-
- function nsUpdateService()
- {
- gPref = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
- gOS = Components.classes["@mozilla.org/observer-service;1"]
- .getService(Components.interfaces.nsIObserverService);
- gRDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]
- .getService(Components.interfaces.nsIRDFService);
-
- this.watchForUpdates();
-
- var pbi = gPref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
- pbi.addObserver(PREF_UPDATE_APP_AUTOUPDATEENABLED, this, false);
- pbi.addObserver(PREF_UPDATE_APP_ENABLED, this, false);
- pbi.addObserver(PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED, this, false);
- pbi.addObserver(PREF_UPDATE_EXTENSIONS_ENABLED, this, false);
- pbi.addObserver(PREF_UPDATE_INTERVAL, this, false);
- pbi.addObserver(PREF_UPDATE_APP_INTERVAL, this, false);
- pbi.addObserver(PREF_UPDATE_EXTENSIONS_INTERVAL, this, false);
-
- // Observe xpcom-shutdown to unhook pref branch observers above to avoid
- // shutdown leaks.
- gOS.addObserver(this, "xpcom-shutdown", false);
-
- // Reset update state from previous session if an app update was installed.
- if (gPref.prefHasUserValue(PREF_UPDATE_APP_PERFORMED))
- gPref.clearUserPref(PREF_UPDATE_APP_PERFORMED);
- }
-
- nsUpdateService.prototype = {
- _updateObserver: null,
- _appAutoUpdateEnabled: true,
- _extAutoUpdateEnabled: true,
-
- /////////////////////////////////////////////////////////////////////////////
- // nsIUpdateService
- watchForUpdates: function nsUpdateService_watchForUpdates ()
- {
- // This is called when the app starts, so check to see if the time interval
- // expired between now and the last time an automated update was performed.
- // now is the same one that was started last time.
- this._appAutoUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_APP_AUTOUPDATEENABLED);
- this._extAutoUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED);
- if (!this._appAutoUpdateEnabled && !this._extAutoUpdateEnabled)
- return;
-
- this._makeTimer(gPref.getIntPref(PREF_UPDATE_INTERVAL));
- },
-
- _getAllowedTypes: function nsUpdateService__getAllowedTypes(aRequestedTypes)
- {
- // Figure out what types we're allowed to update. These options
- // differ from PREF_UPDATE_*_AUTOUPDATEENABLED since they effectively
- // shut down the update UI if the administrator/distributor has configured
- // a build to have disallowed these types of update.
- var extUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED);
- var appUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_APP_ENABLED);
-
- var types = 0;
- if (extUpdateEnabled) {
- if (aRequestedTypes & nsIUpdateItem.TYPE_EXTENSION)
- types |= nsIUpdateItem.TYPE_EXTENSION;
- if (aRequestedTypes & nsIUpdateItem.TYPE_THEME)
- types |= nsIUpdateItem.TYPE_THEME;
- }
- if (appUpdateEnabled &&
- (aRequestedTypes & nsIUpdateItem.TYPE_APP))
- types |= nsIUpdateItem.TYPE_APP;
-
- return types;
- },
-
- checkForUpdates: function nsUpdateService_checkForUpdates (aItems, aItemCount, aUpdateTypes, aSourceEvent, aParentWindow)
- {
- var types = this._getAllowedTypes(aUpdateTypes);
-
- // Nothing to update
- if (!types) {
- var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
- .getService(Components.interfaces.nsIStringBundleService);
- var bundle = sbs.createBundle("chrome://mozapps/locale/update/update.properties");
- var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
- .getService(Components.interfaces.nsIPromptService);
- ps.alert(aParentWindow,
- bundle.GetStringFromName("updatesdisabledtitle"),
- bundle.GetStringFromName("updatesdisabledmessage"));
- return;
- }
-
- switch (aSourceEvent) {
- case nsIUpdateService.SOURCE_EVENT_MISMATCH:
- case nsIUpdateService.SOURCE_EVENT_USER:
- if (aSourceEvent == nsIUpdateService.SOURCE_EVENT_USER &&
- gPref.getBoolPref(PREF_UPDATE_APP_PERFORMED)) {
- var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
- .getService(Components.interfaces.nsIStringBundleService);
- var bundle = sbs.createBundle("chrome://mozapps/locale/update/update.properties");
- var brandBundle = sbs.createBundle("chrome://global/locale/brand.properties");
- var brandShortName = brandBundle.GetStringFromName("brandShortName");
- var message = bundle.formatStringFromName("appupdateperformedmessage",
- [brandShortName, brandShortName], 2);
- var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
- .getService(Components.interfaces.nsIPromptService);
- ps.alert(aParentWindow,
- bundle.GetStringFromName("appupdateperformedtitle"),
- message);
- return;
- }
-
- var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
- .getService(Components.interfaces.nsIWindowMediator);
- var wizard = wm.getMostRecentWindow("Update:Wizard");
- if (wizard)
- wizard.focus();
- else {
- var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
- .getService(Components.interfaces.nsIWindowWatcher);
- var ary = Components.classes["@mozilla.org/supports-array;1"]
- .createInstance(Components.interfaces.nsISupportsArray);
- var updateTypes = Components.classes["@mozilla.org/supports-PRUint8;1"]
- .createInstance(Components.interfaces.nsISupportsPRUint8);
- updateTypes.data = types;
- ary.AppendElement(updateTypes);
- var sourceEvent = Components.classes["@mozilla.org/supports-PRUint8;1"]
- .createInstance(Components.interfaces.nsISupportsPRUint8);
- sourceEvent.data = aSourceEvent;
- ary.AppendElement(sourceEvent);
- for (var i = 0; i < aItems.length; ++i)
- ary.AppendElement(aItems[i]);
-
- var features = "chrome,centerscreen";
- if (aSourceEvent == nsIUpdateService.SOURCE_EVENT_MISMATCH) {
- features += ",modal"; // Must block in mismatch mode since there's
- // no main evt loop yet.
- }
- // This *must* be modal so as not to break startup! This code is invoked before
- // the main event loop is initiated (via checkForMismatches).
- ww.openWindow(aParentWindow, "chrome://mozapps/content/update/update.xul",
- "", features, ary);
- }
- break;
- case nsIUpdateService.SOURCE_EVENT_BACKGROUND:
- // Rather than show a UI, call the checkForUpdates function directly here.
- // The Browser's inline front end update notification system listens for the
- // updates that this function broadcasts.
- this.checkForUpdatesInternal([], 0, types, aSourceEvent);
-
- break;
- }
- },
-
- _canUpdate: function (aPreference, aSourceEvent, aUpdateTypes)
- {
- // Always can update if the autoupdate preference is set, otherwise,
- // allow updates only when not in backround update mode, i.e. when the user
- // explicitly asked.
- return aPreference ? true
- : aSourceEvent != nsIUpdateService.SOURCE_EVENT_BACKGROUND;
- },
-
- checkForUpdatesInternal: function nsUpdateService_checkForUpdatesInternal (aItems, aItemCount, aUpdateTypes, aSourceEvent)
- {
- var types = this._getAllowedTypes(aUpdateTypes);
-
- // Listen for notifications sent out by the app updater (implemented here) and the
- // extension updater (implemented in nsExtensionItemUpdater)
- var canUpdate;
- this._updateObserver = new nsUpdateObserver(types, aSourceEvent, this);
- var os = Components.classes["@mozilla.org/observer-service;1"]
- .getService(Components.interfaces.nsIObserverService);
- if (types & nsIUpdateItem.TYPE_APP) {
- if (this._canUpdate(this._appAutoUpdateEnabled, aSourceEvent, types)) {
- gOS.addObserver(this._updateObserver, "Update:App:Ended", false);
-
- this._currentVersion = new nsAppUpdateInfo();
- this._newestVersion = new nsAppUpdateInfo();
-
- if (!this._updateObserver.appUpdater) {
- this._updateObserver.appUpdater = new nsAppUpdater(this);
- this._updateObserver.appUpdater.checkForUpdates();
- }
- }
- }
- if (types & nsIUpdateItem.TYPE_ADDON) { // TYPE_EXTENSION, TYPE_ANY, etc.
- if (this._canUpdate(this._extAutoUpdateEnabled, aSourceEvent, types)) {
- gOS.addObserver(this._updateObserver, "Update:Extension:Started", false);
- gOS.addObserver(this._updateObserver, "Update:Extension:Item-Ended", false);
- gOS.addObserver(this._updateObserver, "Update:Extension:Ended", false);
-
- var em = Components.classes["@mozilla.org/extensions/manager;1"]
- .getService(Components.interfaces.nsIExtensionManager);
- em.update(aItems, aItems.length, false);
- }
- }
-
- if (aSourceEvent == nsIUpdateService.SOURCE_EVENT_BACKGROUND &&
- (this._appAutoUpdateEnabled || this._extAutoUpdateEnabled)) {
- if (types & nsIUpdateItem.TYPE_ADDON)
- gPref.setIntPref(PREF_UPDATE_EXTENSIONS_LASTUPDATEDATE, this._nowInMilliseconds / 1000);
- if (types & nsIUpdateItem.TYPE_APP)
- gPref.setIntPref(PREF_UPDATE_APP_LASTUPDATEDATE, this._nowInMilliseconds / 1000);
- }
- },
-
- get updateCount()
- {
- // The number of available updates is the number of extension/theme/other
- // updates + 1 for an application update, if one is available.
- var updateCount = this.extensionUpdatesAvailable;
- if (this.appUpdatesAvailable)
- ++updateCount;
- return updateCount;
- },
-
- get updateSeverity()
- {
- return gPref.getIntPref(PREF_UPDATE_SEVERITY);
- },
-
- _appUpdatesAvailable: undefined,
- get appUpdatesAvailable()
- {
- if (this._appUpdatesAvailable === undefined) {
- return (gPref.prefHasUserValue(PREF_UPDATE_APP_UPDATESAVAILABLE) &&
- gPref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE));
- }
- return this._appUpdatesAvailable;
- },
- set appUpdatesAvailable(aValue)
- {
- this._appUpdatesAvailable = aValue;
- return aValue;
- },
-
- _extensionUpdatesAvailable: undefined,
- get extensionUpdatesAvailable()
- {
- if (this._extensionUpdatesAvailable === undefined)
- return gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT);
- return this._extensionUpdatesAvailable;
- },
- set extensionUpdatesAvailable(aValue)
- {
- this._extensionUpdatesAvailable = aValue;
- return aValue;
- },
-
- _newestVersion: null,
- get newestVersion()
- {
- return this._newestVersion;
- },
- _currentVersion: null,
- get currentVersion()
- {
- return this._currentVersion;
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsITimerCallback
- _shouldUpdate: function nsUpdateService__shouldUpdate (aIntervalPref, aLastCheckPref)
- {
- var interval = gPref.getIntPref(aIntervalPref);
- var lastUpdateTime = gPref.getIntPref(aLastCheckPref);
- return ((Math.round(this._nowInMilliseconds/1000) - lastUpdateTime) > Math.round(interval/1000));
- },
-
- notify: function nsUpdateService_notify (aTimer)
- {
- var types = 0;
- if (this._shouldUpdate(PREF_UPDATE_EXTENSIONS_INTERVAL,
- PREF_UPDATE_EXTENSIONS_LASTUPDATEDATE)) {
- types |= nsIUpdateItem.TYPE_ADDON;
- }
- if (this._shouldUpdate(PREF_UPDATE_APP_INTERVAL,
- PREF_UPDATE_APP_LASTUPDATEDATE)) {
- types |= nsIUpdateItem.TYPE_APP;
- }
- if (types)
- this.checkForUpdatesInternal([], 0, types,
- nsIUpdateService.SOURCE_EVENT_BACKGROUND);
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsIObserver
- observe: function nsUpdateService_observe (aSubject, aTopic, aData)
- {
- switch (aTopic) {
- case "nsPref:changed":
- var needsNotification = false;
- switch (aData) {
- case PREF_UPDATE_APP_AUTOUPDATEENABLED:
- case PREF_UPDATE_APP_ENABLED:
- this._appAutoUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_APP_AUTOUPDATEENABLED);
- if (!this._appAutoUpdateEnabled) {
- this._clearAppUpdatePrefs();
- needsNotification = true;
- }
- else {
- // Do an initial check NOW to update any FE components and kick off the
- // timer.
- this.checkForUpdatesInternal([], 0, nsIUpdateItem.TYPE_APP,
- nsIUpdateService.SOURCE_EVENT_BACKGROUND);
- }
- break;
- case PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED:
- case PREF_UPDATE_EXTENSIONS_ENABLED:
- this._extAutoUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED);
- if (!this._extAutoUpdateEnabled) {
- // Unset prefs used by the update service to signify extension updates
- if (gPref.prefHasUserValue(PREF_UPDATE_EXTENSIONS_COUNT))
- gPref.clearUserPref(PREF_UPDATE_EXTENSIONS_COUNT);
- needsNotification = true;
- }
- else {
- // Do an initial check NOW to update any FE components and kick off the
- // timer.
- this.checkForUpdatesInternal([], 0, nsIUpdateItem.TYPE_ADDON,
- nsIUpdateService.SOURCE_EVENT_BACKGROUND);
- }
- break;
- case PREF_UPDATE_INTERVAL:
- case PREF_UPDATE_APP_INTERVAL:
- case PREF_UPDATE_EXTENSIONS_INTERVAL:
- this._makeTimer(gPref.getIntPref(PREF_UPDATE_INTERVAL));
- break;
- }
-
- if (needsNotification) {
- var os = Components.classes["@mozilla.org/observer-service;1"]
- .getService(Components.interfaces.nsIObserverService);
- var backgroundEvt = Components.interfaces.nsIUpdateService.SOURCE_EVENT_BACKGROUND;
- gOS.notifyObservers(null, "Update:Ended", backgroundEvt.toString());
- }
- break;
- case "xpcom-shutdown":
- gOS.removeObserver(this, "xpcom-shutdown");
-
- // Clean up held observers etc to avoid leaks.
- var pbi = gPref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
- pbi.removeObserver(PREF_UPDATE_APP_AUTOUPDATEENABLED, this);
- pbi.removeObserver(PREF_UPDATE_APP_ENABLED, this);
- pbi.removeObserver(PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED, this);
- pbi.removeObserver(PREF_UPDATE_EXTENSIONS_ENABLED, this);
- pbi.removeObserver(PREF_UPDATE_INTERVAL, this);
- pbi.removeObserver(PREF_UPDATE_EXTENSIONS_INTERVAL, this);
-
- // Release strongly held services.
- gPref = null;
- gRDF = null;
- gOS = null;
- if (this._timer) {
- this._timer.cancel();
- this._timer = null;
- }
- break;
- }
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsUpdateService
- _timer: null,
- _makeTimer: function nsUpdateService__makeTimer (aDelay)
- {
- if (!this._timer)
- this._timer = Components.classes["@mozilla.org/timer;1"]
- .createInstance(Components.interfaces.nsITimer);
- this._timer.cancel();
- this._timer.initWithCallback(this, aDelay,
- Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
- },
-
- get _nowInMilliseconds ()
- {
- var d = new Date();
- return Date.UTC(d.getUTCFullYear(),
- d.getUTCMonth(),
- d.getUTCDay(),
- d.getUTCHours(),
- d.getUTCMinutes(),
- d.getUTCSeconds(),
- d.getUTCMilliseconds());
- },
-
- _clearAppUpdatePrefs: function nsUpdateService__clearAppUpdatePrefs ()
- {
- // Unset prefs used by the update service to signify application updates
- if (gPref.prefHasUserValue(PREF_UPDATE_APP_UPDATESAVAILABLE))
- gPref.clearUserPref(PREF_UPDATE_APP_UPDATESAVAILABLE);
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsISupports
- QueryInterface: function nsUpdateService_QueryInterface (aIID)
- {
- if (!aIID.equals(Components.interfaces.nsIUpdateService) &&
- !aIID.equals(Components.interfaces.nsIObserver) &&
- !aIID.equals(Components.interfaces.nsISupports))
- throw Components.results.NS_ERROR_NO_INTERFACE;
- return this;
- }
- };
-
- function nsUpdateObserver(aUpdateTypes, aSourceEvent, aService)
- {
- this._updateTypes = aUpdateTypes;
- this._sourceEvent = aSourceEvent;
- this._service = aService;
- }
-
- nsUpdateObserver.prototype = {
- _updateTypes: 0,
- _sourceEvent: 0,
- _updateState: 0,
- _endedTimer : null,
-
- appUpdater: null,
-
- get _doneUpdating()
- {
- var notBackground = this._sourceEvent != nsIUpdateService.SOURCE_EVENT_BACKGROUND;
- var canUpdateApp = this._service._appAutoUpdateEnabled ||
- (notBackground ? gPref.getBoolPref(PREF_UPDATE_APP_ENABLED)
- : false);
- var canUpdateExt = this._service._extAutoUpdateEnabled ||
- (notBackground ? gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED)
- : false);
-
- var test = 0;
- var updatingApp = (this._updateTypes & nsIUpdateItem.TYPE_APP) &&
- canUpdateApp;
- var updatingExt = (this._updateTypes & nsIUpdateItem.TYPE_ADDON) &&
- canUpdateExt;
-
- if (updatingApp)
- test |= UPDATED_APP;
- if (updatingExt)
- test |= UPDATED_EXTENSIONS;
-
- return (this._updateState & test) == test;
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsIObserver
- observe: function nsUpdateObserver_observe (aSubject, aTopic, aData)
- {
- switch (aTopic) {
- case "Update:Extension:Started":
- // Reset the count
- gPref.setIntPref(PREF_UPDATE_EXTENSIONS_COUNT, 0);
- break;
- case "Update:Extension:Item-Ended":
- var newCount = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT) + 1;
- gPref.setIntPref(PREF_UPDATE_EXTENSIONS_COUNT, newCount);
- var threshold = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD);
- if (this._service.updateSeverity < nsIUpdateService.SEVERITY_HIGH) {
- if (newCount > threshold)
- gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_MEDIUM);
- else
- gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_LOW);
- }
- break;
- case "Update:Extension:Ended":
- this._updateState |= UPDATED_EXTENSIONS;
- break;
- case "Update:App:Ended":
- this._updateState |= UPDATED_APP;
-
- this.appUpdater.destroy();
- this.appUpdater = null;
- break;
- }
-
- if (this._doneUpdating) {
- // Do the finalize stuff on a timer to let other observers have a chance to
- // handle
- if (this._endedTimer)
- this._endedTimer.cancel();
- this._endedTimer = Components.classes["@mozilla.org/timer;1"]
- .createInstance(Components.interfaces.nsITimer);
- this._endedTimer.initWithCallback(this, 0,
- Components.interfaces.nsITimer.TYPE_ONE_SHOT);
- }
- },
-
- notify: function nsUpdateObserver_notify (aTimer)
- {
- // The Inline Browser Update UI uses this notification to refresh its update
- // UI if necessary.
- gOS.notifyObservers(null, "Update:Ended", this._sourceEvent.toString());
-
- // Show update notification UI if:
- // We were updating any types and any item was found
- // We were updating extensions and an extension update was found.
- // We were updating app and an app update was found.
- var updatesAvailable = (((this._updateTypes & nsIUpdateItem.TYPE_EXTENSION) ||
- (this._updateTypes & nsIUpdateItem.TYPE_ANY)) &&
- gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT) != 0);
- if (!updatesAvailable) {
- updatesAvailable = ((this._updateTypes & nsIUpdateItem.TYPE_APP) ||
- (this._updateTypes & nsIUpdateItem.TYPE_ANY)) &&
- gPref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE);
- }
-
- var showNotification = gPref.getBoolPref(PREF_UPDATE_SHOW_SLIDING_NOTIFICATION);
- if (showNotification && updatesAvailable &&
- this._sourceEvent == nsIUpdateService.SOURCE_EVENT_BACKGROUND) {
- var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
- .getService(Components.interfaces.nsIStringBundleService);
- var bundle = sbs.createBundle("chrome://mozapps/locale/update/update.properties");
-
- var alertTitle = bundle.GetStringFromName("updatesAvailableTitle");
- var alertText = bundle.GetStringFromName("updatesAvailableText");
-
- var alerts = Components.classes["@mozilla.org/alerts-service;1"]
- .getService(Components.interfaces.nsIAlertsService);
- alerts.showAlertNotification("chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png",
- alertTitle, alertText, true, "", this);
- }
-
- this.destroy();
- },
-
- destroy: function nsUpdateObserver_destroy ()
- {
- try { gOS.removeObserver(this, "Update:Extension:Started"); } catch (e) { }
- try { gOS.removeObserver(this, "Update:Extension:Item-Ended"); } catch (e) { }
- try { gOS.removeObserver(this, "Update:Extension:Ended"); } catch (e) { }
- try { gOS.removeObserver(this, "Update:App:Ended"); } catch (e) { }
-
- if (this._endedTimer) {
- this._endedTimer.cancel();
- this._endedTimer = null;
- }
- },
-
- ////////////////////////////////////////////////////////////////////////////
- // nsIAlertListener
- onAlertFinished: function nsUpdateObserver_onAlertFinished ()
- {
- },
-
- onAlertClickCallback: function nsUpdateObserver_onAlertClickCallback (aCookie)
- {
- var updates = Components.classes["@mozilla.org/updates/update-service;1"]
- .getService(Components.interfaces.nsIUpdateService);
- updates.checkForUpdates([], 0, Components.interfaces.nsIUpdateItem.TYPE_ANY,
- Components.interfaces.nsIUpdateService.SOURCE_EVENT_USER,
- null);
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsISupports
- QueryInterface: function nsUpdateObserver_QueryInterface (aIID)
- {
- if (!aIID.equals(Components.interfaces.nsIObserver) &&
- !aIID.equals(Components.interfaces.nsIAlertListener) &&
- !aIID.equals(Components.interfaces.nsISupports))
- throw Components.results.NS_ERROR_NO_INTERFACE;
- return this;
- }
- };
-
- ///////////////////////////////////////////////////////////////////////////////
- // App Updater
- function nsAppUpdater(aUpdateService)
- {
- this._service = aUpdateService;
- }
-
- nsAppUpdater.prototype = {
- _service : null,
-
- checkForUpdates: function ()
- {
- var dsURI = gPref.getComplexValue(PREF_UPDATE_APP_URI,
- Components.interfaces.nsIPrefLocalizedString).data;
- dsURI += "?" + Math.round(Math.random() * 1000);
- this._ds = gRDF.GetDataSource(dsURI);
- var rds = this._ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource)
- if (rds.loaded)
- this.onDatasourceLoaded(this._ds);
- else {
- var sink = this._ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
-
- // Creates a strong ref that holds this object past when it falls out of
- // scope in the calling function
- sink.addXMLSinkObserver(this);
- }
- },
-
- destroy: function ()
- {
- var sink = this._ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
- sink.removeXMLSinkObserver(this);
- this._service = null;
- },
-
- /////////////////////////////////////////////////////////////////////////////
- //
- _ncR: function nsUpdateService__ncR (aProperty)
- {
- return gRDF.GetResource("http://home.netscape.com/NC-rdf#" + aProperty);
- },
-
- _getPropertyFromResource: function nsAppUpdater__getPropertyFromResource (aDataSource,
- aSourceResource,
- aProperty)
- {
- var rv;
- try {
- var property = gRDF.GetResource(APP_NS(aProperty));
- rv = this._stringData(aDataSource.GetTarget(aSourceResource, property, true));
- if (rv == "--")
- throw Components.results.NS_ERROR_FAILURE;
- }
- catch (e) {
- return null;
- }
- return rv;
- },
-
- _stringData: function nsAppUpdater__stringData (aLiteralOrResource)
- {
- try {
- var obj = aLiteralOrResource.QueryInterface(Components.interfaces.nsIRDFLiteral);
- return obj.Value;
- }
- catch (e) {
- try {
- obj = aLiteralOrResource.QueryInterface(Components.interfaces.nsIRDFResource);
- return obj.Value;
- }
- catch (e) {}
- }
- return "--";
- },
-
- /////////////////////////////////////////////////////////////////////////////
- //
- onDatasourceLoaded: function nsAppUpdater_onDatasourceLoaded (aDataSource)
- {
- var appID = gPref.getCharPref(PREF_APP_ID);
- var appVersion = gPref.getCharPref(PREF_APP_VERSION);
-
- var appResource = gRDF.GetResource("urn:mozilla:app:" + appID);
- var updatesArc = gRDF.GetResource(APP_NS("updates"));
- var updatesResource = aDataSource.GetTarget(appResource, updatesArc, true);
-
- try {
- updatesResource = updatesResource.QueryInterface(Components.interfaces.nsIRDFResource);
- }
- catch (e) {
- gOS.notifyObservers(null, "Update:App:Error", "");
- gOS.notifyObservers(null, "Update:App:Ended", "");
- return;
- }
-
- var cu = Components.classes["@mozilla.org/rdf/container-utils;1"]
- .getService(Components.interfaces.nsIRDFContainerUtils);
- if (cu.IsContainer(aDataSource, updatesResource)) {
- var c = Components.classes["@mozilla.org/rdf/container;1"]
- .getService(Components.interfaces.nsIRDFContainer);
- c.Init(aDataSource, updatesResource);
-
- var versionChecker = Components.classes["@mozilla.org/updates/version-checker;1"]
- .getService(Components.interfaces.nsIVersionChecker);
-
- var newestVersionObj = { version: appVersion, resource: null };
- var updates = c.GetElements();
- while (updates.hasMoreElements()) {
- var update = updates.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
- var version = this._getPropertyFromResource(aDataSource, update, "version");
- if (!version)
- continue;
- if (versionChecker.compare(appVersion, version) == 0)
- this._parseVersionData(aDataSource, update, this._service._currentVersion);
- else if (versionChecker.compare(newestVersionObj.version, version) < 0) {
- newestVersionObj.version = version;
- newestVersionObj.resource = update;
- }
- }
- if (newestVersionObj.resource)
- this._parseVersionData(aDataSource, newestVersionObj.resource, this._service._newestVersion);
-
- // There is a newer version of the app available or there are any critical
- // patches available update the severity and available updates preferences.
- // XXXben also note if there are langpacks available that match the user's
- // preference if they previously installed an app update when a
- // langpack for their language was not available and they used another
- // in the meantime.
- var haveLanguage = false;
- var patches = this._service._currentVersion.patches;
- var languages = this._service._newestVersion.languages;
- if (languages) {
- var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
- .getService(Components.interfaces.nsIXULChromeRegistry);
- var selectedLocale = cr.getSelectedLocale("global");
- for (var i = 0; i < languages.length; ++i) {
- if (languages[i].internalName == selectedLocale)
- haveLanguage = true;
- }
- }
-
- if ((haveLanguage && (newestVersionObj.version != appVersion)) ||
- (patches && patches.length > 0)) {
- gPref.setIntPref(PREF_UPDATE_SEVERITY, 2);
- gPref.setBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE, true);
- }
- else
- gPref.setBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE, false);
-
- if (!gPref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE)) {
- this._service._clearAppUpdatePrefs();
-
- // Lower the severity to reflect the fact that there are now only Extension/
- // Theme updates available
- var newCount = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT);
- var threshold = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD);
- if (newCount >= threshold)
- gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_MEDIUM);
- else
- gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_LOW);
- }
- }
-
- // The Update Wizard uses this notification to determine that the application
- // update process is now complete.
- gOS.notifyObservers(null, "Update:App:Ended", "");
- },
-
- _parseVersionData: function nsAppUpdater__parseVersionData (aDataSource,
- aUpdateResource,
- aTargetObj)
- {
- aTargetObj.updateVersion = this._getPropertyFromResource(aDataSource, aUpdateResource, "version");
- aTargetObj.updateDisplayVersion = this._getPropertyFromResource(aDataSource, aUpdateResource, "displayVersion");
- if (!aTargetObj.updateDisplayVersion)
- aTargetObj.updateDisplayVersion = this._getPropertyFromResource(aDataSource, aUpdateResource, "version");
- aTargetObj.updateInfoURL = this._getPropertyFromResource(aDataSource, aUpdateResource, "infoURL");
-
- aTargetObj.features = this._parseUpdateCollection(aDataSource, aUpdateResource, "features");
- aTargetObj.files = this._parseUpdateCollection(aDataSource, aUpdateResource, "files");
- aTargetObj.optional = this._parseUpdateCollection(aDataSource, aUpdateResource, "optional");
- aTargetObj.languages = this._parseUpdateCollection(aDataSource, aUpdateResource, "languages");
- aTargetObj.patches = this._parseUpdateCollection(aDataSource, aUpdateResource, "patches");
- },
-
- _parseUpdateCollection: function nsAppUpdater__parseUpdateCollection (aDataSource,
- aUpdateResource,
- aCollectionName)
- {
- if (!aUpdateResource)
- return null;
-
- var result = [];
-
- var collectionArc = gRDF.GetResource(APP_NS(aCollectionName));
- var collectionResource = aDataSource.GetTarget(aUpdateResource, collectionArc, true);
-
- try {
- collectionResource = collectionResource.QueryInterface(Components.interfaces.nsIRDFResource);
- }
- catch (e) { return null; }
-
- var cu = Components.classes["@mozilla.org/rdf/container-utils;1"]
- .getService(Components.interfaces.nsIRDFContainerUtils);
- if (cu.IsContainer(aDataSource, collectionResource)) {
- var c = Components.classes["@mozilla.org/rdf/container;1"]
- .getService(Components.interfaces.nsIRDFContainer);
- c.Init(aDataSource, collectionResource);
-
- var elements = c.GetElements();
- var fileArc = gRDF.GetResource(APP_NS("file"));
- var platform = getOSKey();
- while (elements.hasMoreElements()) {
- var element = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
- var info = new nsAppUpdateInfoItem();
- info.name = this._getPropertyFromResource(aDataSource, element, "name");
- info.internalName = this._getPropertyFromResource(aDataSource, element, "internalName");
-
- // Each Component has a set of app:file arcs out, which reference resources with two
- // properties: app:platform and app:URL. If we find a resource whose app:platform value
- // matches the platform we're running on, we use the app:URL property on that resource
- // as the XPI URL, otherwise we use the default app:URL property on the Component
- // resource. (It must be a cross-platform piece, e.g. a language pack)
- // XXXben - what to do when platform not supported? We need some way to abort
- // and tell the app that this update is not available.
- var files = aDataSource.GetTargets(element, fileArc, true);
- while (files.hasMoreElements()) {
- var file = files.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
- if (platform == this._getPropertyFromResource(aDataSource, file, "platform")) {
- info.URL = this._getPropertyFromResource(aDataSource, file, "URL");
- break;
- }
- }
- if (!info.URL)
- info.URL = this._getPropertyFromResource(aDataSource, element, "URL");
- info.infoURL = this._getPropertyFromResource(aDataSource, element, "infoURL");
- info.description = this._getPropertyFromResource(aDataSource, element, "description");
- result.push(info);
- }
- }
-
- return result;
- },
-
- onDatasourceError: function (aStatus, aErrorMsg)
- {
- gOS.notifyObservers(null, "Update:App:Error", "");
- gOS.notifyObservers(null, "Update:App:Ended", "");
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsIRDFXMLSinkObserver
- onBeginLoad: function(aSink)
- {
- },
- onInterrupt: function(aSink)
- {
- },
- onResume: function(aSink)
- {
- },
-
- onEndLoad: function(aSink)
- {
- try {
- this._ds = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource);
- this.onDatasourceLoaded(this._ds);
- }
- catch (e) { }
- },
-
- onError: function(aSink, aStatus, aErrorMsg)
- {
- try {
- this._ds = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource);
- this.onDatasourceError(aStatus, aErrorMsg);
- }
- catch (e) { }
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsISupports
- QueryInterface: function nsAppUpdater_QueryInterface (aIID)
- {
- if (!aIID.equals(Components.interfaces.nsIRDFXMLSinkObserver) &&
- !aIID.equals(Components.interfaces.nsISupports))
- throw Components.results.NS_ERROR_NO_INTERFACE;
- return this;
- }
- }
-
- function UpdateItem ()
- {
- }
-
- UpdateItem.prototype = {
- init: function UpdateItem_init (aID,
- aVersion,
- aMinAppVersion,
- aMaxAppVersion,
- aName,
- aRow,
- aXPIURL,
- aIconURL,
- aUpdateRDF,
- aType)
- {
- this._id = aID;
- this._version = aVersion;
- this._minAppVersion = aMinAppVersion;
- this._maxAppVersion = aMaxAppVersion;
- this._name = aName;
- this._row = aRow;
- this._xpiURL = aXPIURL;
- this._iconURL = aIconURL;
- this._updateRDF = aUpdateRDF;
- this._type = aType;
- },
-
- get id() { return this._id; },
- get version() { return this._version; },
- get minAppVersion() { return this._minAppVersion; },
- get maxAppVersion() { return this._maxAppVersion; },
- get name() { return this._name; },
- get row() { return this._row; },
- get xpiURL() { return this._xpiURL; },
- get iconURL() { return this._iconURL },
- get updateRDF() { return this._updateRDF; },
- get type() { return this._type; },
-
- get objectSource()
- {
- return { id : this._id,
- version : this._version,
- minAppVersion : this._minAppVersion,
- maxAppVersion : this._maxAppVersion,
- name : this._name,
- row : this._row,
- xpiURL : this._xpiURL,
- iconURL : this._iconURL,
- updateRDF : this._updateRDF,
- type : this._type
- }.toSource();
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsISupports
- QueryInterface: function UpdateItem_QueryInterface (aIID)
- {
- if (!aIID.equals(Components.interfaces.nsIUpdateItem) &&
- !aIID.equals(Components.interfaces.nsISupports))
- throw Components.results.NS_ERROR_NO_INTERFACE;
- return this;
- }
- };
-
- function nsAppUpdateInfoItem ()
- {
- }
- nsAppUpdateInfoItem.prototype = {
- internalName: "",
- name : "",
- URL : "",
- infoURL : "",
-
- /////////////////////////////////////////////////////////////////////////////
- // nsISupports
- QueryInterface: function nsAppUpdater_QueryInterface (aIID)
- {
- if (!aIID.equals(Components.interfaces.nsIAppUpdateInfo) &&
- !aIID.equals(Components.interfaces.nsISupports))
- throw Components.results.NS_ERROR_NO_INTERFACE;
- return this;
- }
- };
-
- function nsAppUpdateInfo ()
- {
- }
- nsAppUpdateInfo.prototype = {
- updateVersion : "",
- updateDisplayVersion: "",
- updateInfoURL : "",
-
- features : [],
- files : [],
- optional : [],
- languages : [],
- patches : [],
-
- getCollection: function (aCollectionName, aItemCount)
- {
- var collection = aCollectionName in this ? this[aCollectionName] : null;
- aItemCount.value = collection ? collection.length : 0;
- return collection;
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsISupports
- QueryInterface: function nsAppUpdater_QueryInterface (aIID)
- {
- if (!aIID.equals(Components.interfaces.nsIAppUpdateInfoCollection) &&
- !aIID.equals(Components.interfaces.nsISupports))
- throw Components.results.NS_ERROR_NO_INTERFACE;
- return this;
- }
- };
-
- function Version(aMajor, aMinor, aRelease, aBuild, aPlus)
- {
- this.major = aMajor || 0;
- this.minor = aMinor || 0;
- this.release = aRelease || 0;
- this.build = aBuild || 0;
- this.plus = aPlus || 0;
- }
-
- Version.prototype = {
- toString: function Version_toString()
- {
- return this.major + "." + this.minor + "." + this.subminor + "." + this.release + (this.plus ? "+" : "");
- },
-
- compare: function (aVersion)
- {
- var fields = ["major", "minor", "release", "build", "plus"];
-
- for (var i = 0; i < fields.length; ++i) {
- var field = fields[i];
- if (aVersion[field] > this[field])
- return -1;
- else if (aVersion[field] < this[field])
- return 1;
- }
- return 0;
- }
- }
-
- function nsVersionChecker()
- {
- }
-
- nsVersionChecker.prototype = {
- /////////////////////////////////////////////////////////////////////////////
- // nsIVersionChecker
-
- // -ve if B is newer
- // equal if A == B
- // +ve if A is newer
- compare: function nsVersionChecker_compare (aVersionA, aVersionB)
- {
- var a = this._decomposeVersion(aVersionA);
- var b = this._decomposeVersion(aVersionB);
-
- return a.compare(b);
- },
-
- _decomposeVersion: function nsVersionChecker__decomposeVersion (aVersion)
- {
- var plus = 0;
- if (aVersion.charAt(aVersion.length-1) == "+") {
- aVersion = aVersion.substr(0, aVersion.length-1);
- plus = 1;
- }
-
- var parts = aVersion.split(".");
-
- return new Version(this._getValidInt(parts[0]),
- this._getValidInt(parts[1]),
- this._getValidInt(parts[2]),
- this._getValidInt(parts[3]),
- plus);
- },
-
- _getValidInt: function nsVersionChecker__getValidInt (aPartString)
- {
- var integer = parseInt(aPartString);
- if (isNaN(integer))
- return 0;
- return integer;
- },
-
- isValidVersion: function nsVersionChecker_isValidVersion (aVersion)
- {
- var parts = aVersion.split(".");
- if (parts.length == 0)
- return false;
- for (var i = 0; i < parts.length; ++i) {
- var part = parts[i];
- if (i == parts.length - 1) {
- if (part.lastIndexOf("+") != -1)
- parts[i] = part.substr(0, part.length - 1);
- }
- var integer = parseInt(part);
- if (isNaN(integer))
- return false;
- }
- return true;
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsISupports
- QueryInterface: function nsVersionChecker_QueryInterface (aIID)
- {
- if (!aIID.equals(Components.interfaces.nsIVersionChecker) &&
- !aIID.equals(Components.interfaces.nsISupports))
- throw Components.results.NS_ERROR_NO_INTERFACE;
- return this;
- }
- };
-
- var gModule = {
- _firstTime: true,
-
- registerSelf: function (aComponentManager, aFileSpec, aLocation, aType)
- {
- if (this._firstTime) {
- this._firstTime = false;
- throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
- }
- aComponentManager = aComponentManager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
-
- for (var key in this._objects) {
- var obj = this._objects[key];
- aComponentManager.registerFactoryLocation(obj.CID, obj.className, obj.contractID,
- aFileSpec, aLocation, aType);
- }
- },
-
- getClassObject: function (aComponentManager, aCID, aIID)
- {
- if (!aIID.equals(Components.interfaces.nsIFactory))
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-
- for (var key in this._objects) {
- if (aCID.equals(this._objects[key].CID))
- return this._objects[key].factory;
- }
-
- throw Components.results.NS_ERROR_NO_INTERFACE;
- },
-
- _objects: {
- manager: { CID: Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}"),
- contractID: "@mozilla.org/updates/update-service;1",
- className: "Update Service",
- factory: {
- createInstance: function (aOuter, aIID)
- {
- if (aOuter != null)
- throw Components.results.NS_ERROR_NO_AGGREGATION;
-
- return (new nsUpdateService()).QueryInterface(aIID);
- }
- }
- },
- version: { CID: Components.ID("{9408E0A5-509E-45E7-80C1-0F35B99FF7A9}"),
- contractID: "@mozilla.org/updates/version-checker;1",
- className: "Version Checker",
- factory: {
- createInstance: function (aOuter, aIID)
- {
- if (aOuter != null)
- throw Components.results.NS_ERROR_NO_AGGREGATION;
-
- return (new nsVersionChecker()).QueryInterface(aIID);
- }
- }
- },
- item: { CID: Components.ID("{F3294B1C-89F4-46F8-98A0-44E1EAE92518}"),
- contractID: "@mozilla.org/updates/item;1",
- className: "Extension Item",
- factory: {
- createInstance: function (aOuter, aIID)
- {
- if (aOuter != null)
- throw Components.results.NS_ERROR_NO_AGGREGATION;
-
- return new UpdateItem().QueryInterface(aIID);
- }
- }
- }
- },
-
- canUnload: function (aComponentManager)
- {
- return true;
- }
- };
-
- function NSGetModule(compMgr, fileSpec)
- {
- return gModule;
- }
-
-